home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / Managed / Direct3D / Scripting / ShadowVolume.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  79.8 KB  |  1,716 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: ShadowVolume.cpp
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #pragma unmanaged
  9. #include "dxstdafx.h"
  10. #include "resource.h"
  11.  
  12. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  13. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  14.  
  15. // Script functions
  16. HRESULT InitializeScriptEngine();
  17. HRESULT LoadScript(LPWSTR pScriptFileName);
  18. HRESULT UpdatePlayerPosition(double appTime, float __nogc* pX, float __nogc* pY, float __nogc* pZ);
  19. HRESULT UpdatePlayerRotationX(double appTime, D3DXMATRIX __nogc* pMatrix);
  20. HRESULT UpdatePlayerRotationY(double appTime, D3DXMATRIX __nogc* pMatrix);
  21. HRESULT UpdatePlayerRotationZ(double appTime, D3DXMATRIX __nogc* pMatrix);
  22.  
  23. #define DEFMESHFILENAME L"dwarf\\dwarf.x"
  24. #define MAX_NUM_LIGHTS 6
  25. #define ADJACENCY_EPSILON 0.0001f
  26. #define EXTRUDE_EPSILON 0.1f
  27. #define AMBIENT 0.10f
  28.  
  29. enum RENDER_TYPE { RENDERTYPE_SCENE, RENDERTYPE_SHADOWVOLUME, RENDERTYPE_COMPLEXITY };
  30.  
  31. D3DXVECTOR4 g_vShadowColor[MAX_NUM_LIGHTS] =
  32. {
  33.     D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 0.2f ),
  34.     D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 0.2f ),
  35.     D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 0.2f ),
  36.     D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 0.2f ),
  37.     D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 0.2f ),
  38.     D3DXVECTOR4( 0.0f, 1.0f, 1.0f, 0.2f )
  39. };
  40.  
  41.  
  42. struct LIGHTINITDATA
  43. {
  44.     D3DXVECTOR3 Position;
  45.     D3DXVECTOR4 Color;
  46. public:
  47.     LIGHTINITDATA() { }
  48.     LIGHTINITDATA( D3DXVECTOR3 P, D3DXVECTOR4 C )
  49.     {
  50.         Position = P;
  51.         Color = C;
  52.     }
  53. };
  54. LIGHTINITDATA g_LightInit[MAX_NUM_LIGHTS] =
  55. {
  56.     LIGHTINITDATA( D3DXVECTOR3( -2.0f, 3.0f, -3.0f ), D3DXVECTOR4( 11.0f, 11.0f, 11.0f, 1.0f ) ),
  57. #if MAX_NUM_LIGHTS > 1
  58.     LIGHTINITDATA(  D3DXVECTOR3( 2.0f, 3.0f, -3.0f ), D3DXVECTOR4( 11.0f, 11.0f, 11.0f, 1.0f ) ),
  59. #endif
  60. #if MAX_NUM_LIGHTS > 2
  61.     LIGHTINITDATA(  D3DXVECTOR3( -2.0f, 3.0f, 3.0f ), D3DXVECTOR4( 11.0f, 11.0f, 11.0f, 1.0f ) ),
  62. #endif
  63. #if MAX_NUM_LIGHTS > 3
  64.     LIGHTINITDATA(  D3DXVECTOR3( 2.0f, 3.0f, 3.0f ), D3DXVECTOR4( 11.0f, 11.0f, 11.0f, 1.0f ) ),
  65. #endif
  66. #if MAX_NUM_LIGHTS > 4
  67.     LIGHTINITDATA(  D3DXVECTOR3( -2.0f, 3.0f, 0.0f ), D3DXVECTOR4( 15.0f, 0.0f, 0.0f, 1.0f ) ),
  68. #endif
  69. #if MAX_NUM_LIGHTS > 5
  70.     LIGHTINITDATA(  D3DXVECTOR3( 2.0f, 3.0f, 0.0f ), D3DXVECTOR4( 0.0f, 0.0f, 15.0f, 1.0f ) )
  71. #endif
  72. };
  73.  
  74. struct POSTPROCVERT
  75. {
  76.     float x, y, z;
  77.     float rhw;
  78.  
  79.     const static D3DVERTEXELEMENT9 Decl[2];
  80. };
  81.  
  82. const D3DVERTEXELEMENT9 POSTPROCVERT::Decl[2] =
  83. {
  84.     { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0 },
  85.     D3DDECL_END()
  86. };
  87.  
  88.  
  89. struct SHADOWVERT
  90. {
  91.     D3DXVECTOR3 Position;
  92.     D3DXVECTOR3 Normal;
  93.  
  94.     const static D3DVERTEXELEMENT9 Decl[3];
  95. };
  96.  
  97. const D3DVERTEXELEMENT9 SHADOWVERT::Decl[3] =
  98. {
  99.     { 0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  100.     { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0 },
  101.     D3DDECL_END()
  102. };
  103.  
  104.  
  105. struct MESHVERT
  106. {
  107.     D3DXVECTOR3 Position;
  108.     D3DXVECTOR3 Normal;
  109.     D3DXVECTOR2 Tex;
  110.  
  111.     const static D3DVERTEXELEMENT9 Decl[4];
  112. };
  113.  
  114. const D3DVERTEXELEMENT9 MESHVERT::Decl[4] =
  115. {
  116.     { 0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  117.     { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0 },
  118.     { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
  119.     D3DDECL_END()
  120. };
  121.  
  122.  
  123. struct CEdgeMapping
  124. {
  125.     int m_anOldEdge[2];  // vertex index of the original edge
  126.     int m_aanNewEdge[2][2]; // vertex indexes of the new edge
  127.                             // First subscript = index of the new edge
  128.                             // Second subscript = index of the vertex for the edge
  129.  
  130. public:
  131.     CEdgeMapping()
  132.     {
  133.         FillMemory( m_anOldEdge, sizeof(m_anOldEdge), -1 );
  134.         FillMemory( m_aanNewEdge, sizeof(m_aanNewEdge), -1 );
  135.     }
  136. };
  137.  
  138.  
  139. struct CLight
  140. {
  141.     D3DXVECTOR3 m_Position;  // Light position
  142.     D3DXVECTOR4 m_Color;     // Light color
  143.     D3DXMATRIXA16 m_mWorld;  // World transform
  144. };
  145.  
  146.  
  147. //--------------------------------------------------------------------------------------
  148. // Global variables
  149. //--------------------------------------------------------------------------------------
  150. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  151. ID3DXSprite*            g_pTextSprite = NULL;   // Sprite for batching draw text calls
  152. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  153. IDirect3DTexture9*      g_pDefaultTex = NULL;   // Default texture for faces without one
  154. IDirect3DVertexDeclaration9* g_pMeshDecl = NULL; // Vertex declaration for the meshes
  155. IDirect3DVertexDeclaration9* g_pShadowDecl = NULL;// Vertex declaration for the shadow volume
  156. IDirect3DVertexDeclaration9* g_pPProcDecl = NULL;// Vertex declaration for post-process quad rendering
  157. CFirstPersonCamera      g_Camera;               // Viewer's camera
  158. CModelViewerCamera      g_MCamera;              // Camera for mesh control
  159. CModelViewerCamera      g_LCamera;              // Camera for easy light movement control
  160. D3DXHANDLE              g_hRenderShadow;        // Technique handle for rendering shadow
  161. D3DXHANDLE              g_hShowShadow;          // Technique handle for showing shadow volume
  162. D3DXHANDLE              g_hRenderScene;         // Technique handle for rendering scene
  163. D3DXMATRIXA16           g_mWorldScaling;        // Scaling to apply to mesh
  164. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  165. bool                    g_bShowShadowVolume = false;  // Whether the shadow volume is visibly shown.
  166. RENDER_TYPE             g_RenderType = RENDERTYPE_SCENE;  // Type of rendering to perform
  167. bool                    g_bModelMovementMode = false;  // If true, camera movement keys move the model instead of the camera.
  168. int                     g_nNumLights = 2;       // Number of active lights
  169. CDXUTMesh               g_Background[2];        // Background meshes
  170. D3DXMATRIXA16           g_mWorldBack[2];        // Additional scaling and translation for background meshes
  171. int                     g_nCurrBackground = 0;  // Current background mesh
  172. CDXUTMesh               g_LightMesh;            // Mesh to represent the light source
  173. CDXUTMesh               g_Mesh;                 // The mesh object
  174. ID3DXMesh*              g_pShadowMesh = NULL;   // The shadow volume mesh
  175. CDXUTDialog             g_HUD;                  // dialog for standard controls
  176. CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
  177. D3DXMATRIXA16           g_mProjection;
  178. CLight                  g_aLights[MAX_NUM_LIGHTS];  // Light objects
  179. bool                    g_bLeftButtonDown = false;
  180. bool                    g_bRightButtonDown = false;
  181. bool                    g_bMiddleButtonDown = false;
  182.  
  183. //--------------------------------------------------------------------------------------
  184. // UI control IDs
  185. //--------------------------------------------------------------------------------------
  186. #define IDC_TOGGLEFULLSCREEN    1
  187. #define IDC_TOGGLEREF           3
  188. #define IDC_CHANGEDEVICE        4
  189. #define IDC_CHANGESCRIPT        5
  190.  
  191.  
  192. //--------------------------------------------------------------------------------------
  193. // Forward declarations 
  194. //--------------------------------------------------------------------------------------
  195. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  196. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  197. void    CALLBACK ModifySettingsDlg( CDXUTDialog* pSettingsDialog );
  198. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  199. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  200. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  201. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  202. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  203. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  204. void    CALLBACK MouseProc( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos );
  205. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  206. void    CALLBACK OnLostDevice();
  207. void    CALLBACK OnDestroyDevice();
  208.  
  209. void    InitApp();
  210. HRESULT LoadMesh( IDirect3DDevice9* pd3dDevice, WCHAR* strFileName, ID3DXMesh** ppMesh );
  211. void    RenderText();
  212.  
  213.  
  214.  
  215. //--------------------------------------------------------------------------------------
  216. // Takes an array of CEdgeMapping objects, then returns an index for the edge in the
  217. // table if such entry exists, or returns an index at which a new entry for the edge
  218. // can be written.
  219. // nV1 and nV2 are the vertex indexes for the old edge.
  220. // nCount is the number of elements in the array.
  221. // The function returns -1 if an available entry cannot be found.  In reality,
  222. // this should never happens as we should have allocated enough memory.
  223. int FindEdgeInMappingTable( int nV1, int nV2, CEdgeMapping *pMapping, int nCount )
  224. {
  225.     for( int i = 0; i < nCount; ++i )
  226.     {
  227.         // If both vertex indexes of the old edge in mapping entry are -1, then
  228.         // we have searched every valid entry without finding a match.  Return
  229.         // this index as a newly created entry.
  230.         if( ( pMapping[i].m_anOldEdge[0] == -1 && pMapping[i].m_anOldEdge[1] == -1 ) ||
  231.  
  232.             // Or if we find a match, return the index.
  233.             ( pMapping[i].m_anOldEdge[1] == nV1 && pMapping[i].m_anOldEdge[0] == nV2 ) )
  234.         {
  235.             return i;
  236.         }
  237.     }
  238.  
  239.     return -1;  // We should never reach this line
  240. }
  241.  
  242.  
  243. //--------------------------------------------------------------------------------------
  244. // Takes a mesh and generate a new mesh from it that contains the degenerate invisible
  245. // quads for shadow volume extrusion.
  246. HRESULT GenerateShadowMesh( IDirect3DDevice9 *pd3dDevice, ID3DXMesh *pMesh, ID3DXMesh **ppOutMesh )
  247. {
  248.     HRESULT hr = S_OK;
  249.     ID3DXMesh *pInputMesh;
  250.  
  251.     if( !ppOutMesh )
  252.         return E_INVALIDARG;
  253.     *ppOutMesh = NULL;
  254.  
  255.     // Convert the input mesh to a format same as the output mesh using 32-bit index.
  256.     hr = pMesh->CloneMesh( D3DXMESH_32BIT, SHADOWVERT::Decl, pd3dDevice, &pInputMesh );
  257.     if( FAILED( hr ) )
  258.         return hr;
  259.  
  260.     DXUTTRACE( L"Input mesh has %u vertices, %u faces\n", pInputMesh->GetNumVertices(), pInputMesh->GetNumFaces() );
  261.  
  262.     // Generate adjacency information
  263.     DWORD *pdwAdj = new DWORD[3 * pInputMesh->GetNumFaces()];
  264.     DWORD *pdwPtRep = new DWORD[pInputMesh->GetNumVertices()];
  265.     if( !pdwAdj || !pdwPtRep )
  266.     {
  267.         delete[] pdwAdj; delete[] pdwPtRep;
  268.         pInputMesh->Release();
  269.         return E_OUTOFMEMORY;
  270.     }
  271.  
  272.     hr = pInputMesh->GenerateAdjacency( ADJACENCY_EPSILON, pdwAdj );
  273.     if( FAILED( hr ) )
  274.     {
  275.         delete[] pdwAdj; delete[] pdwPtRep;
  276.         pInputMesh->Release();
  277.         return hr;
  278.     }
  279.  
  280.     pInputMesh->ConvertAdjacencyToPointReps( pdwAdj, pdwPtRep );
  281.     delete[] pdwAdj;
  282.  
  283.     SHADOWVERT *pVBData = NULL;
  284.     DWORD *pdwIBData = NULL;
  285.  
  286.     pInputMesh->LockVertexBuffer( 0, (LPVOID*)&pVBData );
  287.     pInputMesh->LockIndexBuffer( 0, (LPVOID*)&pdwIBData );
  288.  
  289.     if( pVBData && pdwIBData )
  290.     {
  291.         // Maximum number of unique edges = Number of faces * 3
  292.         DWORD dwNumEdges = pInputMesh->GetNumFaces() * 3;
  293.         CEdgeMapping *pMapping = new CEdgeMapping[dwNumEdges];
  294.         if( pMapping )
  295.         {
  296.             int nNumMaps = 0;  // Number of entries that exist in pMapping
  297.  
  298.             // Create a new mesh
  299.             ID3DXMesh *pNewMesh;
  300.             hr = D3DXCreateMesh( pInputMesh->GetNumFaces() + dwNumEdges * 2,
  301.                                  pInputMesh->GetNumFaces() * 3,
  302.                                  D3DXMESH_32BIT,
  303.                                  SHADOWVERT::Decl,
  304.                                  pd3dDevice,
  305.                                  &pNewMesh );
  306.             if( SUCCEEDED( hr ) )
  307.             {
  308.                 SHADOWVERT *pNewVBData = NULL;
  309.                 DWORD *pdwNewIBData = NULL;
  310.  
  311.                 pNewMesh->LockVertexBuffer( 0, (LPVOID*)&pNewVBData );
  312.                 pNewMesh->LockIndexBuffer( 0, (LPVOID*)&pdwNewIBData );
  313.  
  314.                 // nNextIndex is the array index in IB that the next vertex index value
  315.                 // will be store at.
  316.                 int nNextIndex = 0;
  317.  
  318.                 if( pNewVBData && pdwNewIBData )
  319.                 {
  320.                     ZeroMemory( pNewVBData, pNewMesh->GetNumVertices() * pNewMesh->GetNumBytesPerVertex() );
  321.                     ZeroMemory( pdwNewIBData, sizeof(DWORD) * pNewMesh->GetNumFaces() * 3 );
  322.  
  323.                     // pNextOutVertex is the location to write the next
  324.                     // vertex to.
  325.                     SHADOWVERT *pNextOutVertex = pNewVBData;
  326.  
  327.                     // Iterate through the faces.  For each face, output new
  328.                     // vertices and face in the new mesh, and write its edges
  329.                     // to the mapping table.
  330.  
  331.                     for( UINT f = 0; f < pInputMesh->GetNumFaces(); ++f )
  332.                     {
  333.                         // Copy the vertex data for all 3 vertices
  334.                         CopyMemory( pNextOutVertex, pVBData + pdwIBData[f * 3], sizeof(SHADOWVERT) );
  335.                         CopyMemory( pNextOutVertex + 1, pVBData + pdwIBData[f * 3 + 1], sizeof(SHADOWVERT) );
  336.                         CopyMemory( pNextOutVertex + 2, pVBData + pdwIBData[f * 3 + 2], sizeof(SHADOWVERT) );
  337.  
  338.                         // Write out the face
  339.                         pdwNewIBData[nNextIndex++] = f * 3;
  340.                         pdwNewIBData[nNextIndex++] = f * 3 + 1;
  341.                         pdwNewIBData[nNextIndex++] = f * 3 + 2;
  342.  
  343.                         // Compute the face normal and assign it to
  344.                         // the normals of the vertices.
  345.                         D3DXVECTOR3 v1, v2;  // v1 and v2 are the edge vectors of the face
  346.                         D3DXVECTOR3 vNormal;
  347.                         v1 = *(D3DXVECTOR3*)(pNextOutVertex + 1) - *(D3DXVECTOR3*)pNextOutVertex;
  348.                         v2 = *(D3DXVECTOR3*)(pNextOutVertex + 2) - *(D3DXVECTOR3*)(pNextOutVertex + 1);
  349.                         D3DXVec3Cross( &vNormal, &v1, &v2 );
  350.                         D3DXVec3Normalize( &vNormal, &vNormal );
  351.  
  352.                         pNextOutVertex->Normal = vNormal;
  353.                         (pNextOutVertex + 1)->Normal = vNormal;
  354.                         (pNextOutVertex + 2)->Normal = vNormal;
  355.  
  356.                         pNextOutVertex += 3;
  357.  
  358.                         // Add the face's edges to the edge mapping table
  359.  
  360.                         // Edge 1
  361.                         int nIndex;
  362.                         int nVertIndex[3] = { pdwPtRep[pdwIBData[f * 3]],
  363.                                               pdwPtRep[pdwIBData[f * 3 + 1]],
  364.                                               pdwPtRep[pdwIBData[f * 3 + 2]] };
  365.                         nIndex = FindEdgeInMappingTable( nVertIndex[0], nVertIndex[1], pMapping, dwNumEdges );
  366.  
  367.                         // If error, we are not able to proceed, so abort.
  368.                         if( -1 == nIndex )
  369.                         {
  370.                             hr = E_INVALIDARG;
  371.                             goto cleanup;
  372.                         }
  373.  
  374.                         if( pMapping[nIndex].m_anOldEdge[0] == -1 && pMapping[nIndex].m_anOldEdge[1] == -1 )
  375.                         {
  376.                             // No entry for this edge yet.  Initialize one.
  377.                             pMapping[nIndex].m_anOldEdge[0] = nVertIndex[0];
  378.                             pMapping[nIndex].m_anOldEdge[1] = nVertIndex[1];
  379.                             pMapping[nIndex].m_aanNewEdge[0][0] = f * 3;
  380.                             pMapping[nIndex].m_aanNewEdge[0][1] = f * 3 + 1;
  381.  
  382.                             ++nNumMaps;
  383.                         } else
  384.                         {
  385.                             // An entry is found for this edge.  Create
  386.                             // a quad and output it.
  387.                             assert( nNumMaps > 0 );
  388.  
  389.                             pMapping[nIndex].m_aanNewEdge[1][0] = f * 3;      // For clarity
  390.                             pMapping[nIndex].m_aanNewEdge[1][1] = f * 3 + 1;
  391.  
  392.                             // First triangle
  393.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][1];
  394.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  395.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  396.  
  397.                             // Second triangle
  398.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][1];
  399.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  400.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  401.  
  402.                             // pMapping[nIndex] is no longer needed. Copy the last map entry
  403.                             // over and decrement the map count.
  404.  
  405.                             pMapping[nIndex] = pMapping[nNumMaps-1];
  406.                             FillMemory( &pMapping[nNumMaps-1], sizeof( pMapping[nNumMaps-1] ), 0xFF );
  407.                             --nNumMaps;
  408.                         }
  409.  
  410.                         // Edge 2
  411.                         nIndex = FindEdgeInMappingTable( nVertIndex[1], nVertIndex[2], pMapping, dwNumEdges );
  412.  
  413.                         // If error, we are not able to proceed, so abort.
  414.                         if( -1 == nIndex )
  415.                         {
  416.                             hr = E_INVALIDARG;
  417.                             goto cleanup;
  418.                         }
  419.  
  420.                         if( pMapping[nIndex].m_anOldEdge[0] == -1 && pMapping[nIndex].m_anOldEdge[1] == -1 )
  421.                         {
  422.                             pMapping[nIndex].m_anOldEdge[0] = nVertIndex[1];
  423.                             pMapping[nIndex].m_anOldEdge[1] = nVertIndex[2];
  424.                             pMapping[nIndex].m_aanNewEdge[0][0] = f * 3 + 1;
  425.                             pMapping[nIndex].m_aanNewEdge[0][1] = f * 3 + 2;
  426.  
  427.                             ++nNumMaps;
  428.                         } else
  429.                         {
  430.                             // An entry is found for this edge.  Create
  431.                             // a quad and output it.
  432.                             assert( nNumMaps > 0 );
  433.  
  434.                             pMapping[nIndex].m_aanNewEdge[1][0] = f * 3 + 1;
  435.                             pMapping[nIndex].m_aanNewEdge[1][1] = f * 3 + 2;
  436.  
  437.                             // First triangle
  438.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][1];
  439.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  440.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  441.  
  442.                             // Second triangle
  443.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][1];
  444.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  445.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  446.  
  447.                             // pMapping[nIndex] is no longer needed. Copy the last map entry
  448.                             // over and decrement the map count.
  449.  
  450.                             pMapping[nIndex] = pMapping[nNumMaps-1];
  451.                             FillMemory( &pMapping[nNumMaps-1], sizeof( pMapping[nNumMaps-1] ), 0xFF );
  452.                             --nNumMaps;
  453.                         }
  454.  
  455.                         // Edge 3
  456.                         nIndex = FindEdgeInMappingTable( nVertIndex[2], nVertIndex[0], pMapping, dwNumEdges );
  457.  
  458.                         // If error, we are not able to proceed, so abort.
  459.                         if( -1 == nIndex )
  460.                         {
  461.                             hr = E_INVALIDARG;
  462.                             goto cleanup;
  463.                         }
  464.  
  465.                         if( pMapping[nIndex].m_anOldEdge[0] == -1 && pMapping[nIndex].m_anOldEdge[1] == -1 )
  466.                         {
  467.                             pMapping[nIndex].m_anOldEdge[0] = nVertIndex[2];
  468.                             pMapping[nIndex].m_anOldEdge[1] = nVertIndex[0];
  469.                             pMapping[nIndex].m_aanNewEdge[0][0] = f * 3 + 2;
  470.                             pMapping[nIndex].m_aanNewEdge[0][1] = f * 3;
  471.  
  472.                             ++nNumMaps;
  473.                         } else
  474.                         {
  475.                             // An entry is found for this edge.  Create
  476.                             // a quad and output it.
  477.                             assert( nNumMaps > 0 );
  478.  
  479.                             pMapping[nIndex].m_aanNewEdge[1][0] = f * 3 + 2;
  480.                             pMapping[nIndex].m_aanNewEdge[1][1] = f * 3;
  481.  
  482.                             // First triangle
  483.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][1];
  484.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  485.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  486.  
  487.                             // Second triangle
  488.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][1];
  489.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[1][0];
  490.                             pdwNewIBData[nNextIndex++] = pMapping[nIndex].m_aanNewEdge[0][0];
  491.  
  492.                             // pMapping[nIndex] is no longer needed. Copy the last map entry
  493.                             // over and decrement the map count.
  494.  
  495.                             pMapping[nIndex] = pMapping[nNumMaps-1];
  496.                             FillMemory( &pMapping[nNumMaps-1], sizeof( pMapping[nNumMaps-1] ), 0xFF );
  497.                             --nNumMaps;
  498.                         }
  499.                     }
  500.  
  501.                     // Now the entries in the edge mapping table represent
  502.                     // non-shared edges.  What they mean is that the original
  503.                     // mesh has openings (holes), so we attempt to patch them.
  504.                     // First we need to recreate our mesh with a larger vertex
  505.                     // and index buffers so the patching geometry could fit.
  506.  
  507.                     DXUTTRACE( L"Faces to patch: %d\n", nNumMaps );
  508.  
  509.                     // Create a mesh with large enough vertex and
  510.                     // index buffers.
  511.  
  512.                     SHADOWVERT *pPatchVBData = NULL;
  513.                     DWORD *pdwPatchIBData = NULL;
  514.  
  515.                     ID3DXMesh *pPatchMesh = NULL;
  516.                     // Make enough room in IB for the face and up to 3 quads for each patching face
  517.                     hr = D3DXCreateMesh( nNextIndex / 3 + nNumMaps * 7,
  518.                                          ( pInputMesh->GetNumFaces() + nNumMaps ) * 3,
  519.                                          D3DXMESH_32BIT,
  520.                                          SHADOWVERT::Decl,
  521.                                          pd3dDevice,
  522.                                          &pPatchMesh );
  523.  
  524.                     if( FAILED( hr ) )
  525.                         goto cleanup;
  526.  
  527.                     hr = pPatchMesh->LockVertexBuffer( 0, (LPVOID*)&pPatchVBData );
  528.                     if( SUCCEEDED( hr ) )
  529.                         hr = pPatchMesh->LockIndexBuffer( 0, (LPVOID*)&pdwPatchIBData );
  530.  
  531.                     if( pPatchVBData && pdwPatchIBData )
  532.                     {
  533.                         ZeroMemory( pPatchVBData, sizeof(SHADOWVERT) * ( pInputMesh->GetNumFaces() + nNumMaps ) * 3 );
  534.                         ZeroMemory( pdwPatchIBData, sizeof(DWORD) * ( nNextIndex + 3 * nNumMaps * 7 ) );
  535.  
  536.                         // Copy the data from one mesh to the other
  537.  
  538.                         CopyMemory( pPatchVBData, pNewVBData, sizeof(SHADOWVERT) * pInputMesh->GetNumFaces() * 3 );
  539.                         CopyMemory( pdwPatchIBData, pdwNewIBData, sizeof(DWORD) * nNextIndex );
  540.                     } else
  541.                     {
  542.                         // Some serious error is preventing us from locking.
  543.                         // Abort and return error.
  544.  
  545.                         pPatchMesh->Release();
  546.                         goto cleanup;
  547.                     }
  548.  
  549.                     // Replace pNewMesh with the updated one.  Then the code
  550.                     // can continue working with the pNewMesh pointer.
  551.  
  552.                     pNewMesh->UnlockVertexBuffer();
  553.                     pNewMesh->UnlockIndexBuffer();
  554.                     pNewVBData = pPatchVBData;
  555.                     pdwNewIBData = pdwPatchIBData;
  556.                     pNewMesh->Release();
  557.                     pNewMesh = pPatchMesh;
  558.  
  559.                     // Now, we iterate through the edge mapping table and
  560.                     // for each shared edge, we generate a quad.
  561.                     // For each non-shared edge, we patch the opening
  562.                     // with new faces.
  563.  
  564.                     // nNextVertex is the index of the next vertex.
  565.                     int nNextVertex = pInputMesh->GetNumFaces() * 3;
  566.  
  567.                     for( int i = 0; i < nNumMaps; ++i )
  568.                     {
  569.                         if( pMapping[i].m_anOldEdge[0] != -1 &&
  570.                             pMapping[i].m_anOldEdge[1] != -1 )
  571.                         {
  572.                             // If the 2nd new edge indexes is -1,
  573.                             // this edge is a non-shared one.
  574.                             // We patch the opening by creating new
  575.                             // faces.
  576.                             if( pMapping[i].m_aanNewEdge[1][0] == -1 ||  // must have only one new edge
  577.                                 pMapping[i].m_aanNewEdge[1][1] == -1 )
  578.                             {
  579.                                 // Find another non-shared edge that
  580.                                 // shares a vertex with the current edge.
  581.                                 for( int i2 = i + 1; i2 < nNumMaps; ++i2 )
  582.                                 {
  583.                                     if( pMapping[i2].m_anOldEdge[0] != -1 &&       // must have a valid old edge
  584.                                         pMapping[i2].m_anOldEdge[1] != -1 &&
  585.                                         ( pMapping[i2].m_aanNewEdge[1][0] == -1 || // must have only one new edge
  586.                                         pMapping[i2].m_aanNewEdge[1][1] == -1 ) )
  587.                                     {
  588.                                         int nVertShared = 0;
  589.                                         if( pMapping[i2].m_anOldEdge[0] == pMapping[i].m_anOldEdge[1] )
  590.                                             ++nVertShared;
  591.                                         if( pMapping[i2].m_anOldEdge[1] == pMapping[i].m_anOldEdge[0] )
  592.                                             ++nVertShared;
  593.  
  594.                                         if( 2 == nVertShared )
  595.                                         {
  596.                                             // These are the last two edges of this particular
  597.                                             // opening. Mark this edge as shared so that a degenerate
  598.                                             // quad can be created for it.
  599.  
  600.                                             pMapping[i2].m_aanNewEdge[1][0] = pMapping[i].m_aanNewEdge[0][0];
  601.                                             pMapping[i2].m_aanNewEdge[1][1] = pMapping[i].m_aanNewEdge[0][1];
  602.                                             break;
  603.                                         }
  604.                                         else
  605.                                         if( 1 == nVertShared )
  606.                                         {
  607.                                             // nBefore and nAfter tell us which edge comes before the other.
  608.                                             int nBefore, nAfter;
  609.                                             if( pMapping[i2].m_anOldEdge[0] == pMapping[i].m_anOldEdge[1] )
  610.                                             {
  611.                                                 nBefore = i;
  612.                                                 nAfter = i2;
  613.                                             } else
  614.                                             {
  615.                                                 nBefore = i2;
  616.                                                 nAfter = i;
  617.                                             }
  618.  
  619.                                             // Found such an edge. Now create a face along with two
  620.                                             // degenerate quads from these two edges.
  621.  
  622.                                             pNewVBData[nNextVertex] = pNewVBData[pMapping[nAfter].m_aanNewEdge[0][1]];
  623.                                             pNewVBData[nNextVertex+1] = pNewVBData[pMapping[nBefore].m_aanNewEdge[0][1]];
  624.                                             pNewVBData[nNextVertex+2] = pNewVBData[pMapping[nBefore].m_aanNewEdge[0][0]];
  625.                                             // Recompute the normal
  626.                                             D3DXVECTOR3 v1 = pNewVBData[nNextVertex+1].Position - pNewVBData[nNextVertex].Position;
  627.                                             D3DXVECTOR3 v2 = pNewVBData[nNextVertex+2].Position - pNewVBData[nNextVertex+1].Position;
  628.                                             D3DXVec3Normalize( &v1, &v1 );
  629.                                             D3DXVec3Normalize( &v2, &v2 );
  630.                                             D3DXVec3Cross( &pNewVBData[nNextVertex].Normal, &v1, &v2 );
  631.                                             pNewVBData[nNextVertex+1].Normal = pNewVBData[nNextVertex+2].Normal = pNewVBData[nNextVertex].Normal;
  632.  
  633.                                             pdwNewIBData[nNextIndex] = nNextVertex;
  634.                                             pdwNewIBData[nNextIndex+1] = nNextVertex + 1;
  635.                                             pdwNewIBData[nNextIndex+2] = nNextVertex + 2;
  636.  
  637.                                             // 1st quad
  638.  
  639.                                             pdwNewIBData[nNextIndex+3] = pMapping[nBefore].m_aanNewEdge[0][1];
  640.                                             pdwNewIBData[nNextIndex+4] = pMapping[nBefore].m_aanNewEdge[0][0];
  641.                                             pdwNewIBData[nNextIndex+5] = nNextVertex + 1;
  642.  
  643.                                             pdwNewIBData[nNextIndex+6] = nNextVertex + 2;
  644.                                             pdwNewIBData[nNextIndex+7] = nNextVertex + 1;
  645.                                             pdwNewIBData[nNextIndex+8] = pMapping[nBefore].m_aanNewEdge[0][0];
  646.  
  647.                                             // 2nd quad
  648.  
  649.                                             pdwNewIBData[nNextIndex+9] = pMapping[nAfter].m_aanNewEdge[0][1];
  650.                                             pdwNewIBData[nNextIndex+10] = pMapping[nAfter].m_aanNewEdge[0][0];
  651.                                             pdwNewIBData[nNextIndex+11] = nNextVertex;
  652.  
  653.                                             pdwNewIBData[nNextIndex+12] = nNextVertex + 1;
  654.                                             pdwNewIBData[nNextIndex+13] = nNextVertex;
  655.                                             pdwNewIBData[nNextIndex+14] = pMapping[nAfter].m_aanNewEdge[0][0];
  656.  
  657.                                             // Modify mapping entry i2 to reflect the third edge
  658.                                             // of the newly added face.
  659.  
  660.                                             if( pMapping[i2].m_anOldEdge[0] == pMapping[i].m_anOldEdge[1] )
  661.                                             {
  662.                                                 pMapping[i2].m_anOldEdge[0] = pMapping[i].m_anOldEdge[0];
  663.                                             } else
  664.                                             {
  665.                                                 pMapping[i2].m_anOldEdge[1] = pMapping[i].m_anOldEdge[1];
  666.                                             }
  667.                                             pMapping[i2].m_aanNewEdge[0][0] = nNextVertex + 2;
  668.                                             pMapping[i2].m_aanNewEdge[0][1] = nNextVertex;
  669.  
  670.                                             // Update next vertex/index positions
  671.  
  672.                                             nNextVertex += 3;
  673.                                             nNextIndex += 15;
  674.  
  675.                                             break;
  676.                                         }
  677.                                     }
  678.                                 }
  679.                             } else
  680.                             {
  681.                                 // This is a shared edge.  Create the degenerate quad.
  682.  
  683.                                 // First triangle
  684.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[0][1];
  685.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[0][0];
  686.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[1][0];
  687.  
  688.                                 // Second triangle
  689.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[1][1];
  690.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[1][0];
  691.                                 pdwNewIBData[nNextIndex++] = pMapping[i].m_aanNewEdge[0][0];
  692.                             }
  693.                         }
  694.                     }
  695.                 }
  696.  
  697. cleanup:;
  698.                 if( pNewVBData )
  699.                 {
  700.                     pNewMesh->UnlockVertexBuffer();
  701.                     pNewVBData = NULL;
  702.                 }
  703.                 if( pdwNewIBData )
  704.                 {
  705.                     pNewMesh->UnlockIndexBuffer();
  706.                     pdwNewIBData = NULL;
  707.                 }
  708.  
  709.                 if( SUCCEEDED( hr ) )
  710.                 {
  711.                     // At this time, the output mesh may have an index buffer
  712.                     // bigger than what is actually needed, so we create yet
  713.                     // another mesh with the exact IB size that we need and
  714.                     // output it.  This mesh also uses 16-bit index if
  715.                     // 32-bit is not necessary.
  716.  
  717.                     DXUTTRACE( L"Shadow volume has %u vertices, %u faces.\n", ( pInputMesh->GetNumFaces() + nNumMaps ) * 3, nNextIndex / 3 );
  718.  
  719.                     bool bNeed32Bit = ( pInputMesh->GetNumFaces() + nNumMaps ) * 3 > 65535;
  720.                     ID3DXMesh *pFinalMesh;
  721.                     hr = D3DXCreateMesh( nNextIndex / 3,  // Exact number of faces
  722.                                          ( pInputMesh->GetNumFaces() + nNumMaps ) * 3,
  723.                                          D3DXMESH_WRITEONLY | ( bNeed32Bit ? D3DXMESH_32BIT : 0 ),
  724.                                          SHADOWVERT::Decl,
  725.                                          pd3dDevice,
  726.                                          &pFinalMesh );
  727.                     if( SUCCEEDED( hr ) )
  728.                     {
  729.                         pNewMesh->LockVertexBuffer( 0, (LPVOID*)&pNewVBData );
  730.                         pNewMesh->LockIndexBuffer( 0, (LPVOID*)&pdwNewIBData );
  731.  
  732.                         SHADOWVERT *pFinalVBData = NULL;
  733.                         WORD *pwFinalIBData = NULL;
  734.  
  735.                         pFinalMesh->LockVertexBuffer( 0, (LPVOID*)&pFinalVBData );
  736.                         pFinalMesh->LockIndexBuffer( 0, (LPVOID*)&pwFinalIBData );
  737.  
  738.                         if( pNewVBData && pdwNewIBData && pFinalVBData && pwFinalIBData )
  739.                         {
  740.                             CopyMemory( pFinalVBData, pNewVBData, sizeof(SHADOWVERT) * ( pInputMesh->GetNumFaces() + nNumMaps ) * 3 );
  741.  
  742.                             if( bNeed32Bit )
  743.                                 CopyMemory( pwFinalIBData, pdwNewIBData, sizeof(DWORD) * nNextIndex );
  744.                             else
  745.                             {
  746.                                 for( int i = 0; i < nNextIndex; ++i )
  747.                                     pwFinalIBData[i] = (WORD)pdwNewIBData[i];
  748.                             }
  749.                         }
  750.  
  751.                         if( pNewVBData )
  752.                             pNewMesh->UnlockVertexBuffer();
  753.                         if( pdwNewIBData )
  754.                             pNewMesh->UnlockIndexBuffer();
  755.                         if( pFinalVBData )
  756.                             pFinalMesh->UnlockVertexBuffer();
  757.                         if( pwFinalIBData )
  758.                             pFinalMesh->UnlockIndexBuffer();
  759.  
  760.                         // Release the old
  761.                         pNewMesh->Release();
  762.                         pNewMesh = pFinalMesh;
  763.                     }
  764.  
  765.                     *ppOutMesh = pNewMesh;
  766.                 }
  767.                 else
  768.                     pNewMesh->Release();
  769.             }
  770.             delete[] pMapping;
  771.         } else
  772.             hr = E_OUTOFMEMORY;
  773.     } else
  774.         hr = E_FAIL;
  775.  
  776.     if( pVBData )
  777.         pInputMesh->UnlockVertexBuffer();
  778.  
  779.     if( pdwIBData )
  780.         pInputMesh->UnlockIndexBuffer();
  781.  
  782.     delete[] pdwPtRep;
  783.     pInputMesh->Release();
  784.  
  785.     return hr;
  786. }
  787.  
  788.  
  789. //--------------------------------------------------------------------------------------
  790. // Entry point to the program. Initializes everything and goes into a message processing 
  791. // loop. Idle time is used to render the scene.
  792. //--------------------------------------------------------------------------------------
  793. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  794. {
  795.     // Set the callback functions. These functions allow the sample framework to notify
  796.     // the application about device changes, user input, and windows messages.  The 
  797.     // callbacks are optional so you need only set callbacks for events you're interested 
  798.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  799.     // framework won't be able to reset your device since the application must first 
  800.     // release all device resources before resetting.  Likewise, if you don't handle the 
  801.     // device created/destroyed callbacks then the sample framework won't be able to 
  802.     // recreate your device resources.
  803.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  804.     DXUTSetCallbackDeviceReset( OnResetDevice );
  805.     DXUTSetCallbackDeviceLost( OnLostDevice );
  806.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  807.     DXUTSetCallbackMsgProc( MsgProc );
  808.     DXUTSetCallbackKeyboard( KeyboardProc );
  809.     DXUTSetCallbackMouse( MouseProc );
  810.     DXUTSetCallbackFrameRender( OnFrameRender );
  811.     DXUTSetCallbackFrameMove( OnFrameMove );
  812.  
  813.     // This sample requires a stencil buffer. See the callback function for details.
  814.     CGrowableArray<D3DFORMAT>* pDSFormats = DXUTGetEnumeration()->GetPossibleDepthStencilFormatList();
  815.     pDSFormats->RemoveAll();
  816.     pDSFormats->Add( D3DFMT_D24S8 );
  817.     pDSFormats->Add( D3DFMT_D24X4S4 );
  818.     pDSFormats->Add( D3DFMT_D15S1 );
  819.     pDSFormats->Add( D3DFMT_D24FS8 );
  820.  
  821.     // Show the cursor and clip it when in full screen
  822.     DXUTSetCursorSettings( true, true );
  823.  
  824.     InitApp();
  825.  
  826.     // Initialize the scripting engines application domain
  827.     InitializeScriptEngine();
  828.  
  829.     // Initialize the scaling and translation for the background meshes
  830.     // Hardcode the matrices since we only have two.
  831.     D3DXMATRIXA16 m;
  832.     D3DXMatrixTranslation( &g_mWorldBack[0], 0.0f, 2.0f, 0.0f );
  833.     D3DXMatrixScaling( &g_mWorldBack[1], 0.3f, 0.3f, 0.3f );
  834.     D3DXMatrixTranslation( &m, 0.0f, 1.5f, 0.0f );
  835.     D3DXMatrixMultiply( &g_mWorldBack[1], &g_mWorldBack[1], &m );
  836.  
  837.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  838.     // device for the application. Calling each of these functions is optional, but they
  839.     // allow you to set several options which control the behavior of the framework.
  840.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  841.     DXUTCreateWindow( L"Scripting ShadowVolume" );
  842.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  843.  
  844.     // Pass control to the sample framework for handling the message pump and 
  845.     // dispatching render calls. The sample framework will call your FrameMove 
  846.     // and FrameRender callback when there is idle time between handling window messages.
  847.     DXUTMainLoop();
  848.  
  849.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  850.     // appropriate callback functions and therefore don't require any cleanup code here.
  851.  
  852.     return DXUTGetExitCode();
  853. }
  854.  
  855.  
  856. //--------------------------------------------------------------------------------------
  857. // Initialize the app 
  858. //--------------------------------------------------------------------------------------
  859. void InitApp()
  860. {
  861.     // Initialize dialogs
  862.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  863.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  864.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  865.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  866.  
  867.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 10;
  868.     g_SampleUI.AddComboBox( IDC_CHANGESCRIPT, 0, iY += 24, 190, 22, 0, false );
  869.     g_SampleUI.GetComboBox( IDC_CHANGESCRIPT )->SetDropHeight( 80 );
  870.     g_SampleUI.GetComboBox( IDC_CHANGESCRIPT )->AddItem( L"Not Using Scripts", NULL );
  871.     g_SampleUI.GetComboBox( IDC_CHANGESCRIPT )->AddItem( L"Script #1", L"script1.cs" );
  872.     g_SampleUI.GetComboBox( IDC_CHANGESCRIPT )->AddItem( L"Script #2", L"script2.cs" );
  873.     g_SampleUI.GetComboBox( IDC_CHANGESCRIPT )->AddItem( L"Bad Guy Hacker Script", L"unsecure.cs" );
  874.  
  875.     // Initialize cameras
  876.     g_Camera.SetRotateButtons( true, false, false );
  877.     g_MCamera.SetButtonMasks( MOUSE_RIGHT_BUTTON, 0, 0 );
  878.     g_LCamera.SetButtonMasks( MOUSE_MIDDLE_BUTTON, 0, 0 );
  879.  
  880.     // Initialize the lights
  881.     for( int L = 0; L < MAX_NUM_LIGHTS; ++L )
  882.     {
  883.         D3DXMATRIXA16 m;
  884.         D3DXVECTOR4 v;
  885.         D3DXMatrixScaling( &g_aLights[L].m_mWorld, 0.1f, 0.1f, 0.1f );
  886.         D3DXMatrixTranslation( &m, g_LightInit[L].Position.x,
  887.                                    g_LightInit[L].Position.y,
  888.                                    g_LightInit[L].Position.z );
  889.         D3DXMatrixMultiply( &g_aLights[L].m_mWorld, &g_aLights[L].m_mWorld, &m );
  890.         g_aLights[L].m_Position = g_LightInit[L].Position;
  891.         g_aLights[L].m_Color = g_LightInit[L].Color;
  892.     }
  893. }
  894.  
  895.  
  896. //--------------------------------------------------------------------------------------
  897. // Returns true if a particular depth-stencil format can be created and used with
  898. // an adapter format and backbuffer format combination.
  899. BOOL IsDepthFormatOk( D3DFORMAT DepthFormat,
  900.                       D3DFORMAT AdapterFormat,
  901.                       D3DFORMAT BackBufferFormat )
  902. {
  903.     // Verify that the depth format exists
  904.     HRESULT hr = DXUTGetD3DObject()->CheckDeviceFormat( D3DADAPTER_DEFAULT,
  905.                                                         D3DDEVTYPE_HAL,
  906.                                                         AdapterFormat,
  907.                                                         D3DUSAGE_DEPTHSTENCIL,
  908.                                                         D3DRTYPE_SURFACE,
  909.                                                         DepthFormat );
  910.     if( FAILED( hr ) ) return FALSE;
  911.  
  912.     // Verify that the backbuffer format is valid
  913.     hr = DXUTGetD3DObject()->CheckDeviceFormat( D3DADAPTER_DEFAULT,
  914.                                                 D3DDEVTYPE_HAL,
  915.                                                 AdapterFormat,
  916.                                                 D3DUSAGE_RENDERTARGET,
  917.                                                 D3DRTYPE_SURFACE,
  918.                                                 BackBufferFormat );
  919.     if( FAILED( hr ) ) return FALSE;
  920.  
  921.     // Verify that the depth format is compatible
  922.     hr = DXUTGetD3DObject()->CheckDepthStencilMatch( D3DADAPTER_DEFAULT,
  923.                                                      D3DDEVTYPE_HAL,
  924.                                                      AdapterFormat,
  925.                                                      BackBufferFormat,
  926.                                                      DepthFormat );
  927.  
  928.     return SUCCEEDED(hr);
  929. }
  930.  
  931.  
  932. //--------------------------------------------------------------------------------------
  933. // Called during device initialization, this code checks the device for some 
  934. // minimum set of capabilities, and rejects those that don't pass by returning false.
  935. //--------------------------------------------------------------------------------------
  936. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  937.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  938. {
  939.     // Skip backbuffer formats that don't support alpha blending
  940.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  941.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  942.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  943.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  944.         return false;
  945.  
  946.     // Must support stencil buffer
  947.     if( !IsDepthFormatOk( D3DFMT_D24S8,
  948.                           AdapterFormat,
  949.                           BackBufferFormat ) &&
  950.         !IsDepthFormatOk( D3DFMT_D24X4S4,
  951.                           AdapterFormat,
  952.                           BackBufferFormat ) &&
  953.         !IsDepthFormatOk( D3DFMT_D15S1,
  954.                           AdapterFormat,
  955.                           BackBufferFormat ) &&
  956.         !IsDepthFormatOk( D3DFMT_D24FS8,
  957.                           AdapterFormat,
  958.                           BackBufferFormat ) )
  959.         return false;
  960.  
  961.     return true;
  962. }
  963.  
  964.  
  965. //--------------------------------------------------------------------------------------
  966. // This callback function is called immediately before a device is created to allow the 
  967. // application to modify the device settings. The supplied pDeviceSettings parameter 
  968. // contains the settings that the framework has selected for the new device, and the 
  969. // application can make any desired changes directly to this structure.  Note however that 
  970. // the sample framework will not correct invalid device settings so care must be taken 
  971. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  972. //--------------------------------------------------------------------------------------
  973. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  974. {
  975.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  976.     // then switch to SWVP.
  977.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  978.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  979.     {
  980.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  981.     }
  982.     else
  983.     {
  984.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  985.     }
  986.  
  987.     // Debugging vertex shaders requires either REF or software vertex processing 
  988.     // and debugging pixel shaders requires REF.  
  989. #ifdef DEBUG_VS
  990.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  991.     {
  992.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  993.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  994.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  995.     }
  996. #endif
  997. #ifdef DEBUG_PS
  998.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  999. #endif
  1000.  
  1001.     // This sample requires a stencil buffer.
  1002.     if( IsDepthFormatOk( D3DFMT_D24S8,
  1003.                          pDeviceSettings->AdapterFormat,
  1004.                          pDeviceSettings->pp.BackBufferFormat ) )
  1005.         pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24S8;
  1006.     else
  1007.     if( IsDepthFormatOk( D3DFMT_D24X4S4,
  1008.                          pDeviceSettings->AdapterFormat,
  1009.                          pDeviceSettings->pp.BackBufferFormat ) )
  1010.         pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24X4S4;
  1011.     else
  1012.     if( IsDepthFormatOk( D3DFMT_D24FS8,
  1013.                          pDeviceSettings->AdapterFormat,
  1014.                          pDeviceSettings->pp.BackBufferFormat ) )
  1015.         pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24FS8;
  1016.     else
  1017.     if( IsDepthFormatOk( D3DFMT_D15S1,
  1018.                          pDeviceSettings->AdapterFormat,
  1019.                          pDeviceSettings->pp.BackBufferFormat ) )
  1020.         pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D15S1;
  1021. }
  1022.  
  1023.  
  1024. //--------------------------------------------------------------------------------------
  1025. // This function is called after the D3D Settings Dialog is refreshed, giving the
  1026. // application a chance to modify the dialog contents before being displayed to the
  1027. // user.
  1028. //--------------------------------------------------------------------------------------
  1029. void CALLBACK ModifySettingsDlg( CDXUTDialog* pSettingsDialog )
  1030. {
  1031.     CDXUTComboBox* pComboBox = NULL;
  1032.  
  1033.     pComboBox = pSettingsDialog->GetComboBox( DXUTSETTINGSDLG_DEPTH_STENCIL );
  1034.     for( int i = pComboBox->GetNumItems() - 1; i >= 0; --i )
  1035.     {
  1036.         DXUTComboBoxItem* pItem = pComboBox->GetItem( i );
  1037.         if( pItem->pData != (void*)D3DFMT_D24S8 &&
  1038.             pItem->pData != (void*)D3DFMT_D24X4S4 &&
  1039.             pItem->pData != (void*)D3DFMT_D15S1 &&
  1040.             pItem->pData != (void*)D3DFMT_D24FS8 )
  1041.             pComboBox->RemoveItem( i );
  1042.     }
  1043. }
  1044.  
  1045.  
  1046. // Compute a matrix that scales Mesh to a specified size and centers around origin
  1047. void ComputeMeshScaling( CDXUTMesh &Mesh, D3DXMATRIX *pmScalingCenter )
  1048. {
  1049.     LPVOID pVerts = NULL;
  1050.     D3DXMatrixIdentity( pmScalingCenter );
  1051.     if( SUCCEEDED( Mesh.GetSysMemMesh()->LockVertexBuffer( 0, &pVerts ) ) )
  1052.     {
  1053.         D3DXVECTOR3 vCtr;
  1054.         float fRadius;
  1055.         if( SUCCEEDED( D3DXComputeBoundingSphere( (const D3DXVECTOR3*)pVerts,
  1056.                                                   Mesh.GetSysMemMesh()->GetNumVertices(),
  1057.                                                   Mesh.GetSysMemMesh()->GetNumBytesPerVertex(),
  1058.                                                   &vCtr, &fRadius ) ) )
  1059.         {
  1060.             D3DXMatrixTranslation( pmScalingCenter, -vCtr.x, -vCtr.y, -vCtr.z );
  1061.             D3DXMATRIXA16 m;
  1062.             D3DXMatrixScaling( &m, 1.0f / fRadius,
  1063.                                    1.0f / fRadius,
  1064.                                    1.0f / fRadius );
  1065.             D3DXMatrixMultiply( pmScalingCenter, pmScalingCenter, &m );
  1066.         }
  1067.         Mesh.GetSysMemMesh()->UnlockVertexBuffer();
  1068.     }
  1069. }
  1070.  
  1071.  
  1072. //--------------------------------------------------------------------------------------
  1073. // This callback function will be called immediately after the Direct3D device has been 
  1074. // created, which will happen during application initialization and windowed/full screen 
  1075. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  1076. // resources need to be reloaded whenever the device is destroyed. Resources created  
  1077. // here should be released in the OnDestroyDevice callback. 
  1078. //--------------------------------------------------------------------------------------
  1079. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  1080. {
  1081.     HRESULT hr;
  1082.  
  1083.     // Initialize the vertex declaration
  1084.     V_RETURN( pd3dDevice->CreateVertexDeclaration( MESHVERT::Decl, &g_pMeshDecl ) );
  1085.     V_RETURN( pd3dDevice->CreateVertexDeclaration( SHADOWVERT::Decl, &g_pShadowDecl ) );
  1086.     V_RETURN( pd3dDevice->CreateVertexDeclaration( POSTPROCVERT::Decl, &g_pPProcDecl ) );
  1087.  
  1088.     // Initialize the font
  1089.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  1090.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  1091.                          L"Arial", &g_pFont ) );
  1092.  
  1093.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  1094.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  1095.     // processing, and debugging pixel shaders requires REF.  The 
  1096.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  1097.     // shader debugger.  It enables source level debugging, prevents instruction 
  1098.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  1099.     // against the next higher available software target, which ensures that the 
  1100.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  1101.     // flags will cause slower rendering since the shaders will be unoptimized and 
  1102.     // forced into software.  See the DirectX documentation for more information about 
  1103.     // using the shader debugger.
  1104.     DWORD dwShaderFlags = 0;
  1105.     #ifdef DEBUG_VS
  1106.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  1107.     #endif
  1108.     #ifdef DEBUG_PS
  1109.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  1110.     #endif
  1111.  
  1112.     // Read the D3DX effect file
  1113.     WCHAR str[MAX_PATH];
  1114.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"ShadowVolume.fx" ) );
  1115.  
  1116.     // If this fails, there should be debug output as to 
  1117.     // they the .fx file failed to compile
  1118.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  1119.                                         NULL, &g_pEffect, NULL ) );
  1120.  
  1121.     // Determine the rendering techniques to use based on device caps
  1122.     D3DCAPS9 Caps;
  1123.     V_RETURN( pd3dDevice->GetDeviceCaps( &Caps ) );
  1124.  
  1125.     if( Caps.PixelShaderVersion >= D3DPS_VERSION( 2, 0 ) )
  1126.         g_hRenderScene = g_pEffect->GetTechniqueByName( "RenderScene" );
  1127.     else
  1128.         g_hRenderScene = g_pEffect->GetTechniqueByName( "RenderScene1x" );
  1129.  
  1130.     // If 2-sided stencil is supported, use it.
  1131.     if( Caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED )
  1132.     {
  1133.         g_hRenderShadow = g_pEffect->GetTechniqueByName( "RenderShadowVolume2Sided" );
  1134.         g_hShowShadow = g_pEffect->GetTechniqueByName( "ShowShadowVolume2Sided" );
  1135.     }
  1136.     else
  1137.     {
  1138.         g_hRenderShadow = g_pEffect->GetTechniqueByName( "RenderShadowVolume" );
  1139.         g_hShowShadow = g_pEffect->GetTechniqueByName( "ShowShadowVolume" );
  1140.     }
  1141.  
  1142.     // Load the meshes
  1143.     V_RETURN( g_Background[0].Create( pd3dDevice, L"misc\\cell.x" ) );
  1144.     g_Background[0].SetVertexDecl( pd3dDevice, MESHVERT::Decl );
  1145.     V_RETURN( g_Background[1].Create( pd3dDevice, L"misc\\seafloor.x" ) );
  1146.     g_Background[1].SetVertexDecl( pd3dDevice, MESHVERT::Decl );
  1147.     V_RETURN( g_LightMesh.Create( pd3dDevice, L"misc\\sphere0.x" ) );
  1148.     g_LightMesh.SetVertexDecl( pd3dDevice, MESHVERT::Decl );
  1149.     V_RETURN( g_Mesh.Create( pd3dDevice, DEFMESHFILENAME ) );
  1150.     g_Mesh.SetVertexDecl( pd3dDevice, MESHVERT::Decl );
  1151.  
  1152.     // Compute the scaling matrix for the mesh so that the size of the mesh
  1153.     // that shows on the screen is consistent.
  1154.     ComputeMeshScaling( g_Mesh, &g_mWorldScaling );
  1155.  
  1156.     // Setup the camera's view parameters
  1157.     D3DXVECTOR3 vecEye(0.0f, 0.0f, -5.0f);
  1158.     D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
  1159.     g_Camera.SetViewParams( &vecEye, &vecAt );
  1160.     g_LCamera.SetViewParams( &vecEye, &vecAt );
  1161.     g_MCamera.SetViewParams( &vecEye, &vecAt );
  1162.  
  1163.     // Create the 1x1 white default texture
  1164.     V_RETURN( pd3dDevice->CreateTexture( 1, 1, 1, 0, D3DFMT_A8R8G8B8,
  1165.                                          D3DPOOL_MANAGED, &g_pDefaultTex, NULL ) );
  1166.     D3DLOCKED_RECT lr;
  1167.     V_RETURN( g_pDefaultTex->LockRect( 0, &lr, NULL, 0 ) );
  1168.     *(LPDWORD)lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 );
  1169.     V_RETURN( g_pDefaultTex->UnlockRect( 0 ) );
  1170.  
  1171.     return S_OK;
  1172. }
  1173.  
  1174.  
  1175. //--------------------------------------------------------------------------------------
  1176. // This callback function will be called immediately after the Direct3D device has been 
  1177. // reset, which will happen after a lost device scenario. This is the best location to 
  1178. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  1179. // the device is lost. Resources created here should be released in the OnLostDevice 
  1180. // callback. 
  1181. //--------------------------------------------------------------------------------------
  1182. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  1183.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  1184. {
  1185.     HRESULT hr;
  1186.  
  1187.     if( g_pFont )
  1188.         V_RETURN( g_pFont->OnResetDevice() );
  1189.     if( g_pEffect )
  1190.         V_RETURN( g_pEffect->OnResetDevice() );
  1191.  
  1192.     g_Background[0].RestoreDeviceObjects( pd3dDevice );
  1193.     g_Background[1].RestoreDeviceObjects( pd3dDevice );
  1194.     g_LightMesh.RestoreDeviceObjects( pd3dDevice );
  1195.     g_Mesh.RestoreDeviceObjects( pd3dDevice );
  1196.  
  1197.     // Create a sprite to help batch calls when drawing many lines of text
  1198.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  1199.  
  1200.     // Setup the camera's projection parameters
  1201.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  1202.     g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 20.0f );
  1203.     g_MCamera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  1204.     g_LCamera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  1205.     g_pEffect->SetFloat( "g_fFarClip", 20.0f - EXTRUDE_EPSILON );
  1206.     V( g_pEffect->SetMatrix( "g_mProj", g_Camera.GetProjMatrix() ) );
  1207.  
  1208.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  1209.     g_HUD.SetSize( 170, 170 );
  1210.     g_SampleUI.SetLocation( 0, pBackBufferSurfaceDesc->Height-200 );
  1211.     g_SampleUI.SetSize( pBackBufferSurfaceDesc->Width, 150 );
  1212.  
  1213.     int iY = 10;
  1214.     g_SampleUI.GetControl( IDC_CHANGESCRIPT )->SetLocation( pBackBufferSurfaceDesc->Width - 200, iY += 24 );
  1215.  
  1216.     // Generate the shadow volume mesh
  1217.     GenerateShadowMesh( pd3dDevice, g_Mesh.GetSysMemMesh(), &g_pShadowMesh );
  1218.  
  1219.     return S_OK;
  1220. }
  1221.  
  1222.  
  1223. //--------------------------------------------------------------------------------------
  1224. // This callback function will be called once at the beginning of every frame. This is the
  1225. // best location for your application to handle updates to the scene, but is not 
  1226. // intended to contain actual rendering calls, which should instead be placed in the 
  1227. // OnFrameRender callback.  
  1228. //--------------------------------------------------------------------------------------
  1229. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  1230. {
  1231.     // Update the camera's position based on user input 
  1232.     g_Camera.FrameMove( fElapsedTime );
  1233.     g_MCamera.FrameMove( fElapsedTime );
  1234.     g_LCamera.FrameMove( fElapsedTime );
  1235.  
  1236.     // Let script engine handle this
  1237.     D3DXMATRIX* pMatrix = g_MCamera.GetWorldMatrix();
  1238.     UpdatePlayerRotationX(fTime, pMatrix);
  1239.     UpdatePlayerRotationY(fTime, pMatrix);
  1240.     UpdatePlayerRotationZ(fTime, pMatrix);
  1241.     UpdatePlayerPosition(fTime, (float*)&pMatrix->_41, (float*)&pMatrix->_42, (float*)&pMatrix->_43);
  1242. }
  1243.  
  1244.  
  1245. //--------------------------------------------------------------------------------------
  1246. // Simply renders the entire scene without any shadow handling.
  1247. void RenderScene( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, bool bRenderLight )
  1248. {
  1249.     HRESULT hr;
  1250.     D3DXMATRIXA16 mWorldView;
  1251.     D3DXMATRIXA16 mViewProj;
  1252.     D3DXMATRIXA16 mWorldViewProjection;
  1253.  
  1254.     // Get the projection & view matrix from the camera class
  1255.     D3DXMatrixMultiply( &mViewProj, g_Camera.GetViewMatrix(), g_Camera.GetProjMatrix() );
  1256.  
  1257.     // Render the lights if requested
  1258.     if( bRenderLight )
  1259.     {
  1260.         D3DXHANDLE hCurrTech;
  1261.         hCurrTech = g_pEffect->GetCurrentTechnique();  // Save the current technique
  1262.         V( g_pEffect->SetTechnique( "RenderSceneAmbient" ) );
  1263.         V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
  1264.         D3DXVECTOR4 vLightMat( 1.0f, 1.0f, 1.0f, 1.0f );
  1265.         V( g_pEffect->SetVector( "g_vMatColor", &vLightMat ) );
  1266.         UINT cPasses;
  1267.         ID3DXMesh *pMesh = g_LightMesh.GetLocalMesh();
  1268.         V( g_pEffect->Begin( &cPasses, 0 ) );
  1269.         for( UINT i = 0; i < cPasses; ++i )
  1270.         {
  1271.             V( g_pEffect->BeginPass( i ) );
  1272.             for( int i = 0; i < g_nNumLights; ++i )
  1273.             {
  1274.                 for( UINT m = 0; m < g_LightMesh.m_dwNumMaterials; ++m )
  1275.                 {
  1276.                     mWorldView = g_aLights[i].m_mWorld * *g_LCamera.GetWorldMatrix() * *g_Camera.GetViewMatrix();
  1277.                     mWorldViewProjection = mWorldView * *g_Camera.GetProjMatrix();
  1278.                     V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
  1279.                     V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  1280.                     V( g_pEffect->SetVector( "g_vAmbient", &g_aLights[i].m_Color ) );
  1281.  
  1282.                     // The effect interface queues up the changes and performs them 
  1283.                     // with the CommitChanges call. You do not need to call CommitChanges if 
  1284.                     // you are not setting any parameters between the BeginPass and EndPass.
  1285.                     V( g_pEffect->CommitChanges() );
  1286.  
  1287.                     V( pMesh->DrawSubset( m ) );
  1288.                 }
  1289.             }
  1290.             V( g_pEffect->EndPass() );
  1291.         }
  1292.         V( g_pEffect->End() );
  1293.         V( g_pEffect->SetTechnique( hCurrTech ) ); // Restore the old technique
  1294.         D3DXVECTOR4 vAmb( AMBIENT, AMBIENT, AMBIENT, 1.0f );
  1295.         V( g_pEffect->SetVector( "g_vAmbient", &vAmb ) );
  1296.     }
  1297.  
  1298.     // Render the background mesh
  1299.     V( pd3dDevice->SetVertexDeclaration( g_pMeshDecl ) );
  1300.     mWorldView = g_mWorldBack[g_nCurrBackground] * *g_Camera.GetViewMatrix();
  1301.     mWorldViewProjection = g_mWorldBack[g_nCurrBackground] * mViewProj;
  1302.     V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  1303.     V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
  1304.     UINT cPasses;
  1305.     V( g_pEffect->Begin( &cPasses, 0 ) );
  1306.     for( UINT i = 0; i < cPasses; ++i )
  1307.     {
  1308.         V( g_pEffect->BeginPass( i ) );
  1309.         ID3DXMesh *pMesh = g_Background[g_nCurrBackground].GetLocalMesh();
  1310.         for( UINT i = 0; i < g_Background[g_nCurrBackground].m_dwNumMaterials; ++i )
  1311.         {
  1312.             V( g_pEffect->SetVector( "g_vMatColor", (D3DXVECTOR4*)&g_Background[g_nCurrBackground].m_pMaterials[i].Diffuse ) );
  1313.             if( g_Background[g_nCurrBackground].m_pTextures[i] )
  1314.                 V( g_pEffect->SetTexture( "g_txScene", g_Background[g_nCurrBackground].m_pTextures[i] ) )
  1315.             else
  1316.                 V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
  1317.             // The effect interface queues up the changes and performs them 
  1318.             // with the CommitChanges call. You do not need to call CommitChanges if 
  1319.             // you are not setting any parameters between the BeginPass and EndPass.
  1320.             V( g_pEffect->CommitChanges() );
  1321.             V( pMesh->DrawSubset( i ) );
  1322.         }
  1323.         V( g_pEffect->EndPass() );
  1324.     }
  1325.     V( g_pEffect->End() );
  1326.  
  1327.     // Render the mesh
  1328.     V( pd3dDevice->SetVertexDeclaration( g_pMeshDecl ) );
  1329.     mWorldView = g_mWorldScaling * *g_MCamera.GetWorldMatrix() * *g_Camera.GetViewMatrix();
  1330.     mWorldViewProjection = mWorldView * *g_Camera.GetProjMatrix();
  1331.     V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  1332.     V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
  1333.     V( g_pEffect->Begin( &cPasses, 0 ) );
  1334.     for( UINT i = 0; i < cPasses; ++i )
  1335.     {
  1336.         V( g_pEffect->BeginPass( i ) );
  1337.         ID3DXMesh *pMesh = g_Mesh.GetLocalMesh();
  1338.         for( UINT i = 0; i < g_Mesh.m_dwNumMaterials; ++i )
  1339.         {
  1340.             V( g_pEffect->SetVector( "g_vMatColor", (D3DXVECTOR4*)&g_Mesh.m_pMaterials[i].Diffuse ) );
  1341.             if( g_Mesh.m_pTextures[i] )
  1342.                 V( g_pEffect->SetTexture( "g_txScene", g_Mesh.m_pTextures[i] ) )
  1343.             else
  1344.                 V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
  1345.             // The effect interface queues up the changes and performs them 
  1346.             // with the CommitChanges call. You do not need to call CommitChanges if 
  1347.             // you are not setting any parameters between the BeginPass and EndPass.
  1348.             V( g_pEffect->CommitChanges() );
  1349.             V( pMesh->DrawSubset( i ) );
  1350.         }
  1351.         V( g_pEffect->EndPass() );
  1352.     }
  1353.     V( g_pEffect->End() );
  1354. }
  1355.  
  1356.  
  1357. //--------------------------------------------------------------------------------------
  1358. // This callback function will be called at the end of every frame to perform all the 
  1359. // rendering calls for the scene, and it will also be called if the window needs to be 
  1360. // repainted. After this function has returned, the sample framework will call 
  1361. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  1362. //--------------------------------------------------------------------------------------
  1363. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  1364. {
  1365.     HRESULT hr;
  1366.  
  1367.     // Clear the render target and the zbuffer
  1368.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 66, 75, 121), 1.0f, 0 ) );
  1369.  
  1370.     // Render the scene
  1371.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  1372.     {
  1373.         // First, render the scene with only ambient lighting
  1374.         g_pEffect->SetTechnique( "RenderSceneAmbient" );
  1375.         D3DXVECTOR4 vAmb( AMBIENT, AMBIENT, AMBIENT, 1.0f );
  1376.         V( g_pEffect->SetVector( "g_vAmbient", &vAmb ) );
  1377.         RenderScene( pd3dDevice, fTime, fElapsedTime, true );
  1378.  
  1379.         // Now process the lights.  For each light in the scene,
  1380.         // render the shadow volume, then render the scene with
  1381.         // stencil enabled.
  1382.  
  1383.         for( int L = 0; L < g_nNumLights; ++L )
  1384.         {
  1385.             // Clear the stencil buffer
  1386.             if( g_RenderType != RENDERTYPE_COMPLEXITY )
  1387.                 V( pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, D3DCOLOR_ARGB(0, 170, 170, 170), 1.0f, 0 ) );
  1388.  
  1389.             D3DXVECTOR4 vLight( g_aLights[L].m_Position.x, g_aLights[L].m_Position.y, g_aLights[L].m_Position.z, 1.0f );
  1390.             D3DXVec4Transform( &vLight, &vLight, g_LCamera.GetWorldMatrix() );
  1391.             D3DXVec4Transform( &vLight, &vLight, g_Camera.GetViewMatrix() );
  1392.             V( g_pEffect->SetVector( "g_vLightView", &vLight ) );
  1393.             V( g_pEffect->SetVector( "g_vLightColor", &g_aLights[L].m_Color ) );
  1394.  
  1395.             // Render the shadow volume
  1396.             switch( g_RenderType )
  1397.             {
  1398.                 case RENDERTYPE_COMPLEXITY:
  1399.                     g_pEffect->SetTechnique( "RenderShadowVolumeComplexity" );
  1400.                     break;
  1401.                 case RENDERTYPE_SHADOWVOLUME:
  1402.                     g_pEffect->SetTechnique( g_hShowShadow );
  1403.                     break;
  1404.                 default:
  1405.                     g_pEffect->SetTechnique( g_hRenderShadow );
  1406.             }
  1407.  
  1408.             g_pEffect->SetVector( "g_vShadowColor", &g_vShadowColor[L] );
  1409.  
  1410.             // If there was an error generating the shadow volume,
  1411.             // skip rendering the shadow mesh.  The scene will show
  1412.             // up without shadow.
  1413.             if( g_pShadowMesh )
  1414.             {
  1415.                 V( pd3dDevice->SetVertexDeclaration( g_pShadowDecl ) );
  1416.                 UINT cPasses;
  1417.                 V( g_pEffect->Begin( &cPasses, 0 ) );
  1418.                 for( UINT i = 0; i < cPasses; ++i )
  1419.                 {
  1420.                     V( g_pEffect->BeginPass( i ) );
  1421.                     V( g_pEffect->CommitChanges() );
  1422.                     V( g_pShadowMesh->DrawSubset( 0 ) );
  1423.                     V( g_pEffect->EndPass() );
  1424.                 }
  1425.                 V( g_pEffect->End() );
  1426.             }
  1427.  
  1428.             //
  1429.             // Render the scene with stencil and lighting enabled.
  1430.             //
  1431.             if( g_RenderType != RENDERTYPE_COMPLEXITY )
  1432.             {
  1433.                 g_pEffect->SetTechnique( g_hRenderScene );
  1434.                 RenderScene( pd3dDevice, fTime, fElapsedTime, false );
  1435.             }
  1436.         }
  1437.  
  1438.         if( g_RenderType == RENDERTYPE_COMPLEXITY )
  1439.         {
  1440.             // Clear the render target
  1441.             V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0 ) );
  1442.  
  1443.             // Render scene complexity visualization
  1444.             const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  1445.             POSTPROCVERT quad[4] =
  1446.             {
  1447.                 { -0.5f,                                                -0.5f, 0.5f, 1.0f },
  1448.                 { pd3dsdBackBuffer->Width-0.5f,                         -0.5f, 0.5f, 1.0f },
  1449.                 { -0.5f,                        pd3dsdBackBuffer->Height-0.5f, 0.5f, 1.0f },
  1450.                 { pd3dsdBackBuffer->Width-0.5f, pd3dsdBackBuffer->Height-0.5f, 0.5f, 1.0f }
  1451.             };
  1452.  
  1453.             pd3dDevice->SetVertexDeclaration( g_pPProcDecl );
  1454.             g_pEffect->SetTechnique( "RenderComplexity" );
  1455.             UINT cPasses;
  1456.             g_pEffect->Begin( &cPasses, 0 );
  1457.             for( UINT p = 0; p < cPasses; ++p )
  1458.             {
  1459.                 g_pEffect->BeginPass( p );
  1460.                 pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, quad, sizeof(POSTPROCVERT) );
  1461.                 g_pEffect->EndPass();
  1462.             }
  1463.             g_pEffect->End();
  1464.         }
  1465.  
  1466.         // Miscellaneous rendering
  1467.         RenderText();
  1468.         g_HUD.OnRender( fElapsedTime );
  1469.         g_SampleUI.OnRender( fElapsedTime );
  1470.  
  1471.         V( pd3dDevice->EndScene() );
  1472.     }
  1473. }
  1474.  
  1475.  
  1476. //--------------------------------------------------------------------------------------
  1477. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  1478. // efficient text rendering.
  1479. //--------------------------------------------------------------------------------------
  1480. void RenderText()
  1481. {
  1482.     // The helper object simply helps keep track of text position, and color
  1483.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  1484.     // If NULL is passed in as the sprite object, then it will work however the 
  1485.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  1486.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  1487.     const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  1488.  
  1489.     // Output statistics
  1490.     txtHelper.Begin();
  1491.     txtHelper.SetInsertionPos( 5, 5 );
  1492.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  1493.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  1494.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  1495.  
  1496.     // Draw help
  1497.     if( g_bShowHelp )
  1498.     {
  1499.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-80 );
  1500.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  1501.         txtHelper.DrawTextLine( L"Controls (F1 to hide):" );
  1502.  
  1503.         txtHelper.SetInsertionPos( 20, pd3dsdBackBuffer->Height-65 );
  1504.         txtHelper.DrawTextLine( L"Camera control: Left mouse\n"
  1505.                                 L"Mesh control: Right mouse\n"
  1506.                                 L"Light control: Middle mouse\n"
  1507.                                 L"Quit: ESC" );
  1508.     }
  1509.     else
  1510.     {
  1511.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-25 );
  1512.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1513.         txtHelper.DrawTextLine( L"Press F1 for help" );
  1514.     }
  1515.  
  1516.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1517.     if( !(g_bLeftButtonDown || g_bMiddleButtonDown || g_bRightButtonDown) )
  1518.     {
  1519.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width / 2 - 90, pd3dsdBackBuffer->Height - 40 );
  1520.         txtHelper.DrawTextLine( L"\nW/S/A/D/Q/E to move camera." );
  1521.     } else
  1522.     {
  1523.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width / 2 - 70, pd3dsdBackBuffer->Height - 40 );
  1524.         if( g_bLeftButtonDown )
  1525.         {
  1526.             txtHelper.DrawTextLine( L"Camera Control Mode" );
  1527.         } else
  1528.         if( g_bMiddleButtonDown )
  1529.         {
  1530.             txtHelper.DrawTextLine( L"Light Control Mode" );
  1531.         }
  1532.         if( g_bRightButtonDown )
  1533.         {
  1534.             txtHelper.DrawTextLine( L"Model Control Mode" );
  1535.         }
  1536.         txtHelper.SetInsertionPos( pd3dsdBackBuffer->Width / 2 - 130, pd3dsdBackBuffer->Height - 25 );
  1537.         txtHelper.DrawTextLine( L"Move mouse to rotate. W/S/A/D/Q/E to move." );
  1538.     }
  1539.  
  1540.     if( g_RenderType == RENDERTYPE_COMPLEXITY )
  1541.     {
  1542.         txtHelper.SetInsertionPos( 5, 70 );
  1543.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1544.         txtHelper.DrawTextLine( L"Shadow volume complexity:" );
  1545.         txtHelper.SetInsertionPos( 5, 90 );
  1546.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 1.0f, 1.0f ) );
  1547.         txtHelper.DrawTextLine( L"1 to 5 fills\n" );
  1548.         txtHelper.SetForegroundColor( D3DXCOLOR( 0.0f, 0.0f, 1.0f, 1.0f ) );
  1549.         txtHelper.DrawTextLine( L"6 to 10 fills\n" );
  1550.         txtHelper.SetForegroundColor( D3DXCOLOR( 0.0f, 1.0f, 1.0f, 1.0f ) );
  1551.         txtHelper.DrawTextLine( L"11 to 20 fills\n" );
  1552.         txtHelper.SetForegroundColor( D3DXCOLOR( 0.0f, 1.0f, 0.0f, 1.0f ) );
  1553.         txtHelper.DrawTextLine( L"21 to 30 fills\n" );
  1554.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  1555.         txtHelper.DrawTextLine( L"31 to 40 fills\n" );
  1556.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.5f, 0.0f, 1.0f ) );
  1557.         txtHelper.DrawTextLine( L"41 to 50 fills\n" );
  1558.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );
  1559.         txtHelper.DrawTextLine( L"51 to 70 fills\n" );
  1560.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  1561.         txtHelper.DrawTextLine( L"71 or more fills\n" );
  1562.     }
  1563.  
  1564.     // Display an error message if unable to generate shadow mesh
  1565.     if( !g_pShadowMesh )
  1566.     {
  1567.         txtHelper.SetInsertionPos( 5, 35 );
  1568.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );
  1569.         txtHelper.DrawTextLine( L"Unable to generate closed shadow volume for this mesh\n" );
  1570.         txtHelper.DrawTextLine( L"No shadow will be rendered" );
  1571.     }
  1572.  
  1573.     txtHelper.End();
  1574. }
  1575.  
  1576.  
  1577. //--------------------------------------------------------------------------------------
  1578. // Before handling window messages, the sample framework passes incoming windows 
  1579. // messages to the application through this callback function. If the application sets 
  1580. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  1581. //--------------------------------------------------------------------------------------
  1582. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  1583. {
  1584.     // Give the dialogs a chance to handle the message first
  1585.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  1586.     if( *pbNoFurtherProcessing )
  1587.         return 0;
  1588.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  1589.     if( *pbNoFurtherProcessing )
  1590.         return 0;
  1591.  
  1592.     // Pass all remaining windows messages to camera so it can respond to user input
  1593.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  1594.     g_MCamera.HandleMessages( hWnd, uMsg, wParam, lParam );
  1595.     g_LCamera.HandleMessages( hWnd, uMsg, wParam, lParam );
  1596.  
  1597.     return 0;
  1598. }
  1599.  
  1600.  
  1601. //--------------------------------------------------------------------------------------
  1602. // As a convenience, the sample framework inspects the incoming windows messages for
  1603. // keystroke messages and decodes the message parameters to pass relevant keyboard
  1604. // messages to the application.  The framework does not remove the underlying keystroke 
  1605. // messages, which are still passed to the application's MsgProc callback.
  1606. //--------------------------------------------------------------------------------------
  1607. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  1608. {
  1609.     if( bKeyDown )
  1610.     {
  1611.         switch( nChar )
  1612.         {
  1613.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  1614.         }
  1615.     }
  1616. }
  1617.  
  1618.  
  1619. void CALLBACK MouseProc( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta, int xPos, int yPos )
  1620. {
  1621.     g_bLeftButtonDown = bLeftButtonDown;
  1622.     g_bMiddleButtonDown = bMiddleButtonDown;
  1623.     g_bRightButtonDown = bRightButtonDown;
  1624.  
  1625.     bool bOldModelMovementMode = g_bModelMovementMode;
  1626.     g_bModelMovementMode = g_bRightButtonDown;
  1627.     if( bOldModelMovementMode && !g_bModelMovementMode )
  1628.     {
  1629.         // Enable camera movement. Disable model movement
  1630.         g_Camera.SetEnablePositionMovement( true );
  1631.         g_MCamera.SetEnablePositionMovement( false );
  1632.     } else
  1633.     if( !bOldModelMovementMode && g_bModelMovementMode )
  1634.     {
  1635.         // Enable model movement. Disable camera movement
  1636.         g_Camera.SetEnablePositionMovement( false );
  1637.         g_MCamera.SetEnablePositionMovement( true );
  1638.     }
  1639. }
  1640.  
  1641.  
  1642. //--------------------------------------------------------------------------------------
  1643. // Handles the GUI events
  1644. //--------------------------------------------------------------------------------------
  1645. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  1646. {
  1647.     switch( nControlID )
  1648.     {
  1649.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  1650.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  1651.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  1652.         case IDC_CHANGESCRIPT:
  1653.             if( g_SampleUI.GetComboBox( IDC_CHANGESCRIPT )->GetSelectedData() )
  1654.             {
  1655.                 // Find the script file
  1656.                 WCHAR strPath[MAX_PATH];
  1657.                 DXUTFindDXSDKMediaFileCch( strPath, sizeof(strPath) / sizeof(WCHAR), 
  1658.                     (LPCWSTR)g_SampleUI.GetComboBox( IDC_CHANGESCRIPT )->GetSelectedData()) ;
  1659.                 
  1660.                 LoadScript(strPath);
  1661.             }
  1662.             else
  1663.             {
  1664.                 // Load an 'empty' script file to turn off scripting
  1665.                 LoadScript(NULL);
  1666.             }
  1667.  
  1668.             break;
  1669.     }
  1670. }
  1671.  
  1672.  
  1673. //--------------------------------------------------------------------------------------
  1674. // This callback function will be called immediately after the Direct3D device has 
  1675. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  1676. // in the OnResetDevice callback should be released here, which generally includes all 
  1677. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  1678. // information about lost devices.
  1679. //--------------------------------------------------------------------------------------
  1680. void CALLBACK OnLostDevice()
  1681. {
  1682.     g_Background[0].InvalidateDeviceObjects();
  1683.     g_Background[1].InvalidateDeviceObjects();
  1684.     g_LightMesh.InvalidateDeviceObjects();
  1685.     g_Mesh.InvalidateDeviceObjects();
  1686.     SAFE_RELEASE( g_pShadowMesh );
  1687.  
  1688.     if( g_pFont )
  1689.         g_pFont->OnLostDevice();
  1690.     if( g_pEffect )
  1691.         g_pEffect->OnLostDevice();
  1692.     SAFE_RELEASE(g_pTextSprite);
  1693. }
  1694.  
  1695.  
  1696. //--------------------------------------------------------------------------------------
  1697. // This callback function will be called immediately after the Direct3D device has 
  1698. // been destroyed, which generally happens as a result of application termination or 
  1699. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  1700. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  1701. //--------------------------------------------------------------------------------------
  1702. void CALLBACK OnDestroyDevice()
  1703. {
  1704.     g_Background[0].Destroy();
  1705.     g_Background[1].Destroy();
  1706.     g_LightMesh.Destroy();
  1707.     g_Mesh.Destroy();
  1708.  
  1709.     SAFE_RELEASE( g_pDefaultTex );
  1710.     SAFE_RELEASE( g_pEffect );
  1711.     SAFE_RELEASE( g_pFont );
  1712.     SAFE_RELEASE( g_pMeshDecl );
  1713.     SAFE_RELEASE( g_pShadowDecl );
  1714.     SAFE_RELEASE( g_pPProcDecl );
  1715. }
  1716.